import os.path
import traceback
import Image
import gtk.glade
import shutil
import subprocess

#from pybookshelf import plugin
from pybs.plugin import construct_attr as ca
from pybs import exceptions
from pybs import collection
from pybs import settings
from pybs import genres
from pybs import html
from pybs import xml
from pybs import log
from pybs import path
from . import fb2doc
from . import fb2editgui

PLUGIN_NAME = _("FictionBook2 plugin")
PLUGIN_SUPPORTED_FILE_TYPES = ("fb2", "fb2.zip")

class FormatError(exceptions.BookFormatError):
    pass

# common plugin functions
def extract_metadata(filepath):
    """
    Function that extracts all possible metadata from the specified file
    """
    metadata = []
    book = fb2doc.parse_file(filepath)
    
    metadata.append(ca("title", book.title()))
    metadata += [ca("genre", genre_name) for genre_name, genre_match in book.genres() if genre_match is None]
    metadata += [ca("genre", genre_name, [ ["match", genre_match] ]) for genre_name, genre_match in book.genres() if not genre_match is None]
    metadata += [ca("author", a.format()) for a in book.authors()]
    sequences = dict()
    for s in book.sequences():
        if not s['name'] in sequences:
            sequences[s['name']] = []
        sequences[s['name']].append( ["number", s['number']] ) # (param_name, param_value)
    
    metadata += [ca("sequence", k, sequences[k]) for k in sequences.keys()]
    #metadata += [ca("sequence", s["name"], {'number': s['number']}) for s in book.sequences()]
    return metadata

def preferences_glade_root():
    """
    Return glade object that corresponds to root of preferences window
    
    @return: gtk.glade.XML instance
    """
    # fb2.glade and this file are in the same directory
    base_dir = os.path.dirname(os.path.realpath(__file__))
    xml = gtk.glade.XML(os.path.join(base_dir, "fb2.glade"), root="preferences_widget",
        domain="pybookshelf")
    
    return xml

def preferences_init_widgets_values(xml):
    """
    Initialize widgets in the preferences window
    
    @param xml: gtk.glade.XML instance from previous preferences_glade_root() call
    """
    # load default setting values
    fb2_viewer = settings.get_str("external_viewer", plugin="fb2")
    xml.get_widget("fb2_viewer_text_entry").set_text(fb2_viewer)
    
    fb2_use_internal_viewer = settings.get_boolean("use_internal_viewer", plugin="fb2")
    xml.get_widget("fb2_use_internal_viewer_checkbox").set_active(fb2_use_internal_viewer)
    
def preferences_remember_widget_values(xml):
    """
    Remember values of widgets in the preferences window
    
    @param xml: gtk.glade.XML instance from previous preferences_glade_root() call
    """
    fb2_viewer = xml.get_widget("fb2_viewer_text_entry").get_text()
    settings.set_str("external_viewer", fb2_viewer, plugin="fb2")
    
    fb2_use_internal_viewer = xml.get_widget("fb2_use_internal_viewer_checkbox").get_active()
    settings.set_str("use_internal_viewer", fb2_use_internal_viewer, plugin="fb2")

def read_book(book_path, parent_window):
    """
    Read book, i.e. either generate set of HTML files and images or launch another application

    @param book_path: path to book file
    @param parent_window: parent window, gtk.Window instance
    @return: list of generated files (including images, styles etc), or 
        subprocess.Popen instance of launched application, or
        None if nothing was done
    """
    fb2_viewer = settings.get_str("external_viewer", plugin="fb2")
    fb2_use_internal_viewer = settings.get_boolean("use_internal_viewer", plugin="fb2")
    
    result = None
    
    if fb2_use_internal_viewer:
        log.debug("Use internal viewer for FB2 file")
        # parse fb2 file and display in the tab
        cache_dir = path.get_cache_path("books")
        if not os.path.exists(cache_dir):
            os.mkdir(cache_dir)
            f = path.get_data_path("html", "css", "book.css")
            shutil.copyfile(f, os.path.join(cache_dir, "style.css"))
            
        book_dir = path.make_unique_dir(cache_dir)
        html_file = os.path.join(book_dir, "book.html")
        if not os.path.exists(book_dir):
            os.mkdir(book_dir)
        
        page_files = []
        book = fb2doc.parse_file(book_path)
        html = book.html(path.get_data_path("xml", "fb2html.xsl"))
        fd = open(html_file, "w")
        fd.write(html)
        fd.close()
        page_files.append(html_file)
        
        for img, id, content_type in book.images():
            f = os.path.join(book_dir, id)
            open(f, "wb").write(img)
            page_files.append(f)
        
        result = page_files
    elif "" != fb2_viewer:
        log.debug("Use external viewer")
        # try to execute application

        try:
            p = subprocess.Popen([fb2_viewer, book_path])
            result = p
        except OSError, e:
            log.error("read_book() failed, OSError: %s" % e)
            
    return result

def can_edit_book(book_path):
    return True

def edit_book(book_path, parent_window):
    """
    Display book metadata editing dialog
    
    @param book_path: path to book file
    @param parent_window: gtk.Window instance that should own book edit dialog
    @return: True if book file was modified, False otherwise
    """
    return fb2editgui.edit_book_dialog(book_path, parent_window)

# plugin specific functions
def gen_book_html(file_id, temp_files_dir, presets=None):
    """
    @return: tuple(body, files, book_title), body is a generated html-code, files is a list of 
        created files (full paths), book_title is a book title, extracted from the file or from metadata
    """
    if presets is None:
        presets = dict()
        
    page_template = html.get_html_template("book")
    author_template = html.get_html_template("book_author")
    genre_template = html.get_html_template("book_genre")
    series_template = html.get_html_template("book_series")

    metadata = collection.get_book_metadata(file_id)
    
    book_path = collection.get_book_file(file_id)
    book = fb2doc.parse_file(book_path)
    
    authors_list = []
    genres_list = []
    series = []
    title = ""
    
    for m in metadata:
        try:
            if m['attr_name'] == "author":
                authors_list.append(author_template % {
                    #'author_id': m['attr_value_id'],
                    'author_name': m['attr_value']
                    })
                continue
            
            if m['attr_name'] == "genre":
                match = ""
                
                for param_name, param_value in m['attr_params']:
                    if param_name == "match" and str(param_value) != "100":
                        match = " (%s%%)" % param_value
                    
                genres_list.append(genre_template % {
                    'genre_name': m['attr_value'], # nontranslated genre name
                    'title': genres.expand_genre(m['attr_value']),
                    'match': match
                    #'num_books': number
                    })
                continue
            
            if m['attr_name'] == "sequence":
                for param_name, param_value in m['attr_params']:
                    if param_name != "number":
                        continue

                    try:
                        number = int(param_value)
                    except ValueError:
                        number = 0
                    except TypeError:
                        number = 0
                        
                    if number != 0:
                        number = " (%s)" % number
                    else:
                        number = ""
                    
                    series.append(series_template % {
                        'series_name': m['attr_value'],
                        'title': m['attr_value'] + number
                        })
                continue
            
            if m['attr_name'] == "title":
                title = m['attr_value']
                continue
            
        except KeyError, e:
            log.error("Metadata key error: %s" % e)
            log.error(traceback.format_exc())
    
    authors_list = ", ".join(authors_list)
    genres_list = ", ".join(genres_list)
    
    # translate annotation into html
    annotation = _("<i>No annotation available.</i>")
    annotation_doc = book.annotation_doc()

    if not annotation_doc is None:
        xslt = xml.annotation_xslt()
        annotation = str(xslt(annotation_doc))

    # get covers
    covers_files = book.covers(temp_files_dir, "book_%s_cover_" % file_id)
    cover = ""

    max_cover_width = settings.get_int("ui/cover_max_width_html")
    own_cover_files = []

    for cf in covers_files:
        if not os.path.exists(cf):
            # file doesn't exists so it's safe to add it to own_cover_files
            # in other case it's not safe because that file probably owned
            # by this page some history steps ago
            own_cover_files.append(cf)
            
        # resize image file if it's too wide
        im = Image.open(cf)
        w, h = im.size
        
        if w > max_cover_width: 
            h = (max_cover_width * h) / w
            w = max_cover_width
            im.thumbnail((w, h), resample=1)
            im.save(cf, format=im.format)

        cover = '<img src="file://%s" width="%s" height="%s">' % (cf, w, h)
        break # take just first cover
    
    sequences = ""
    if len(series):
        sequences = _("Series: ") + ", ".join(series)
    
    presets.update({
        'title': title,
        'authors': authors_list,
        'genres': genres_list,
        'annotation': annotation,
        'covers': cover,
        'file_id': file_id,
        'icon_download': html.stock_img_url("download.png"),
        'icon_read': html.stock_img_url("read.png"),
        'icon_edit': html.stock_img_url("edit.png"),
        'sequences': sequences,
        'export_tooltip': _("Export book file into external directory"),
        'readbook_tooltip': _("Read book")
        })
    
    body = page_template % presets
        
    return body, own_cover_files, title












